

#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <ctype.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <stdbool.h>
#include "PL_io.h"
#define PAGE_SIZE  ((size_t)getpagesize())
#define PAGE_MASK ((uint64_t) (long)~(PAGE_SIZE - 1))
//*****************************************************************************
#define FATAL do { fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \
  __LINE__, __FILE__, errno, strerror(errno)); exit(1); } while(0)

#define MAP_SIZE 4096UL  			//映射的内存区大小（一般为一个叶框大小）
#define MAP_MASK (MAP_SIZE - 1)   	//MAP_MASK = 0XFFF
//*****************************************************************************


/*******************************************************
 * 实际物理地址写入4byte数据
 * phyaddr      实际物理地址
 * val          数据
 * ****************************************************/
void Xil_Out32(unsigned long phyaddr, uint32_t  val)
{
	int fd;
	volatile uint8_t *map_base;
	uint64_t base = phyaddr & PAGE_MASK;
	uint64_t pgoffset = phyaddr & (~PAGE_MASK);

	if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1)
	{
		perror("open /dev/mem:");
	}

	map_base = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
			fd, base);
	if(map_base == MAP_FAILED)
	{
		perror("mmap:");
	}
	*(volatile uint32_t *)(map_base + pgoffset) = val;
	close(fd);
	munmap((void *)map_base, PAGE_SIZE);
}
/*******************************************************
 * 实际物理地址读取4byte数据
 * phyaddr      实际物理地址
 * return       数据
 * ****************************************************/
int Xil_In32(unsigned long phyaddr)
{
	int fd;
	uint32_t val;
	volatile uint8_t *map_base;
	uint64_t base = phyaddr & PAGE_MASK;
	uint64_t pgoffset = phyaddr & (~PAGE_MASK);
	//open /dev/mem
	if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1)
	{
		perror("open /dev/mem:");
	}
	//mmap
	map_base = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
			fd, base);
	if(map_base == MAP_FAILED)
	{
		perror("mmap:");
	}
	val = *(volatile uint32_t *)(map_base + pgoffset);
	close(fd);
	munmap((void *)map_base, PAGE_SIZE);

	return val;
}
/*******************************************************
 * 实际物理地址写入2byte数据
 * phyaddr      实际物理地址
 * val          数据
 * ****************************************************/
void Xil_Out16(uint64_t phyaddr, uint16_t val)
{
    int fd;
    volatile uint8_t *map_base;
    uint64_t base = phyaddr & PAGE_MASK;
    uint64_t pgoffset = phyaddr & (~PAGE_MASK);

    if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1)
    {
        perror("open /dev/mem:");
    }

    map_base = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
            fd, base);
    if(map_base == MAP_FAILED)
    {
        perror("mmap:");
    }
    *(volatile uint16_t *)(map_base + pgoffset) = val;
    close(fd);
    munmap((void *)map_base, PAGE_SIZE);
}
/*******************************************************
 * 实际物理地址读取2byte数据
 * phyaddr      实际物理地址
 * return       数据
 * ****************************************************/
int Xil_In16(uint64_t phyaddr)
{
    int fd;
    uint16_t val;
    volatile uint8_t *map_base;
    uint64_t base = phyaddr & PAGE_MASK;
    uint64_t pgoffset = phyaddr & (~PAGE_MASK);
    //open /dev/mem
    if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1)
    {
        perror("open /dev/mem:");
    }
    //mmap
    map_base = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
            fd, base);
    if(map_base == MAP_FAILED)
    {
        perror("mmap:");
    }
    val = *(volatile uint16_t *)(map_base + pgoffset);
    close(fd);
    munmap((void *)map_base, PAGE_SIZE);

    return val;
}
/*******************************************************
 * 实际物理地址写入1byte数据
 * phyaddr      实际物理地址
 * val          数据
 * ****************************************************/
void Xil_Out8(uint64_t phyaddr, uint16_t val)
{
    int fd;
    volatile uint8_t *map_base;
    uint64_t base = phyaddr & PAGE_MASK;
    uint64_t pgoffset = phyaddr & (~PAGE_MASK);

    if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1)
    {
        perror("open /dev/mem:");
    }

    map_base = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
            fd, base);
    if(map_base == MAP_FAILED)
    {
        perror("mmap:");
    }
    *(volatile uint8_t *)(map_base + pgoffset) = val;
    close(fd);
    munmap((void *)map_base, PAGE_SIZE);
}
/*******************************************************
* 实际物理地址读取1byte数据
 * phyaddr      实际物理地址
 * return       数据
 * ****************************************************/
uint8_t Xil_In8(uint64_t phyaddr)
{
    int fd;
    uint8_t val;
    volatile uint8_t *map_base;
    uint64_t base = phyaddr & PAGE_MASK;
    uint64_t pgoffset = phyaddr & (~PAGE_MASK);
    //open /dev/mem
    if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1)
    {
        perror("open /dev/mem:");
    }
    //mmap
    map_base = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
            fd, base);
    if(map_base == MAP_FAILED)
    {
        perror("mmap:");
    }
    val = *(volatile uint8_t *)(map_base + pgoffset);
    close(fd);
    munmap((void *)map_base, PAGE_SIZE);

    return val;
}

/**
* @brief 从实际物理地址读取数据。
* @details 通过 mmap 映射关系，找到对应的实际物理地址对应的虚拟地址，然后读取数据。
* 读取长度，每次最低4字节。
* @param[in] readAddr, unsigned long, 需要操作的物理地址。
* @param[out] buf，unsigned char *, 读取数据的buf地址。
* @param[in] bufLen，unsigned long , buf 参数的容量，4字节为单位，如 unsigned long buf[100]，那么最大能接收100个4字节。
* 用于避免因为buf容量不足，导致素组越界之类的软件崩溃问题。
* @return len，unsigned long, 读取的数据长度，字节为单位。如果读取出错，则返回0，如果正确，则返回对应的长度。
*/
 int Devmem_Read(unsigned long readAddr, uint32_t* buf, unsigned long len)
{
    int i = 0;
    int fd,ret;
    int offset_len = 0;
    void *map_base, *virt_addr;
    off_t addr = readAddr;
    unsigned long littleEndianLength = 0;

    if ((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1)
    {
        fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", __LINE__, __FILE__, errno, strerror(errno));
        return 0;
    }

    /* Map one page */ //将内核空间映射到用户空间
    map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, addr & ~MAP_MASK);
    if(map_base == (void *) -1)
    {
        fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", __LINE__, __FILE__, errno, strerror(errno));
        close(fd);
        return 0;
    }

    for (i = 0; i < len; i++)
    {
        // 翻页处理
        if(offset_len >= MAP_MASK)
        {
            offset_len = 0;
            if(munmap(map_base, MAP_SIZE) == -1)
            {
                fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", __LINE__, __FILE__, errno, strerror(errno));
                close(fd);
                return 0;
            }
            map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, addr & ~MAP_MASK);
            if(map_base == (void *) -1)
            {
                fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", __LINE__, __FILE__, errno, strerror(errno));
                close(fd);
                return 0;
            }
        }

        virt_addr = map_base + (addr & MAP_MASK);	/// 将内核空间映射到用户空间操作
        buf[i] = *((uint32_t *) virt_addr);	// 读取数据
        addr += 4;
        offset_len += 4;
    }

    if(munmap(map_base, MAP_SIZE) == -1)
    {
        fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", __LINE__, __FILE__, errno, strerror(errno));
        close(fd);
        return 0;
    }
    close(fd);
    return i;
}

int Read_PLDDR_BUFF(unsigned int addrOffset, uint32_t* buf, unsigned long len)
{
 int ans=0;
 Devmem_Read(PL_DDR_BASEADDR+addrOffset,  buf,len);
 return ans;
}
